package com.unbiz.common.plugin;

import java.io.File;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.unbiz.common.lang.BaseObject;
import com.unbiz.common.logger.Logger;
import com.unbiz.common.logger.LoggerFactory;
import com.unbiz.common.logger.LoggerProvider;
import com.unbiz.common.mutable.MutableDouble;
import com.unbiz.common.mutable.MutableLong;
import com.unbiz.common.mutable.MutableNumber;

/**
 * T is interface for plugin
 * @author Hunteron-cp
 *
 * @param <T>
 */
public abstract class PluginFactory<T> extends BaseObject<String> {
	
	private static final Map<String,MutableNumber> statisic = new LinkedHashMap<>();
	public static final Logger logger = LoggerFactory.getLogger(PluginFactory.class);
	
	protected boolean enable = true;
	
	public PluginFactory(String key){
		super(key);		
		PluginManager.registerPluginFactory(this);
	}
	
	public abstract String getName();
	
	public abstract T create(Map<String,Object> attributes);
	
	public void destory(){
		
	}
	
	
	public Map<String,Integer> feathersMap(){
		return new HashMap<String,Integer>();
	}
	
	public static long logMetricForCount(String name,long v){
		MutableNumber<Long> value = statisic.get(name);
		if(value==null){
			value = new MutableLong(v);
			statisic.put(name, value);
		}
		else{
			value.set(v+value.getValue());
		}
		return value.longValue();
	}
	
	public static long logMetricForDuration(String name, long durationInMillis) {
		MutableNumber<Long> value = statisic.get(name);
		if(value==null){
			value = new MutableLong(durationInMillis);
			statisic.put(name, value);
		}
		else{
			value.set(durationInMillis);
		}
		return value.longValue();
	}

	/**
	 * Increase the sum specified by <code>name</code> by <code>value</code> only for one item.
	 * 
	 * @param name
	 *           the name of the metric
	 * @param value
	 *           the value added to the metric
	 */
	public static double logMetricForSum(String name, double value) {
		return logMetricForSum(name, value,1);
	}
	
	/**
	 * Increase the metric specified by <code>name</code> by <code>sum</code> for multiple items.
	 * 
	 * @param name
	 *           the name of the metric
	 * @param sum
	 *           the sum value added to the metric
	 * @param quantity
	 *           the quantity to be accumulated
	 */
	public static double logMetricForSum(String name, double sum, int quantity) {
		MutableNumber<Double> value = statisic.get(name);
		if(value==null){
			value = new MutableDouble(sum*quantity);
			statisic.put(name, value);
		}
		else{
			value.set(value.get()+sum*quantity);
		}
		return value.doubleValue();
	}	

	
	public boolean isEnable() {
		return enable;
	}

	public void setEnable(boolean enable) {
		this.enable = enable;
	}
	
	/**
	 * json string
	 * @return
	 */
	public static String metricMap(){
		Map<String,String> values = new LinkedHashMap<>();
		statisic.forEach(
				(k,v)->	values.put(k,v.toString())				
			);
		Object obj= JSON.toJSON(values);
		//invoke toString
		String json= JSON.toJSONString(obj, true); 
		return json;
	}
}
